package org.gitman.agentplatform.ui.api;

import java.awt.Color;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;

import javax.swing.JOptionPane;

import org.gitman.agentplatform.agent.api.InternalAgentInfo;
import org.gitman.agentplatform.core.AgentManager;
import org.gitman.agentplatform.core.PlatformManager;
import org.gitman.agentplatform.core.Simulation;
import org.gitman.agentplatform.core.SimulationStatistic;
import org.gitman.agentplatform.core.exceptions.NoGraphException;
import org.gitman.agentplatform.ui.MainFrame;
import org.gitman.agentplatform.ui.graph.GraphEditor;
import org.gitman.agentplatform.ui.simulation.MultirunDialog;
import org.gitman.agentplatform.ui.summary.MultirunSummaryDialog;
import org.gitman.agentplatform.ui.summary.SummaryPanel;
import org.gitman.agentplatform.ui.utils.LoggingPanel.Level;
import org.gitman.agentplatform.ui.utils.SwingConsole;

import com.mxgraph.model.mxCell;
import com.mxgraph.model.mxIGraphModel;
import com.mxgraph.util.mxConstants;
import com.mxgraph.util.mxUtils;
import com.mxgraph.view.mxGraph;

public class View {
	private static MainFrame mainFrame;
	private int dely = 300;
	private mxGraph graph;
	private MultirunDialog multirunDialog;

	public View(){
		mainFrame = new MainFrame();
		SwingConsole.run(mainFrame);
	}	
	public MainFrame getMainFrame() {
		return mainFrame;
	}
	public void setMainFrame(MainFrame mainFrame) {
		View.mainFrame = mainFrame;
	}
	public void update() {
		mainFrame.getSimulationPanel().fireTableChanged();
	}
	public void init(Collection<InternalAgentInfo> queuedAgentsInfo) throws NoGraphException {
		GraphEditor editor = GraphEditor.getInstance();
		graph = editor.getGraph();
		if(graph == null){
			throw new NoGraphException();
		}
		mxIGraphModel model = graph.getModel();
		model.beginUpdate();
		try{
			Set<Integer> occupiedIDs = new HashSet<Integer>();
			for(InternalAgentInfo info : queuedAgentsInfo){
				occupiedIDs.add(info.getStartVertexID());
			}
			for(Object o : graph.getChildVertices(graph.getDefaultParent())){
				Integer id = Integer.parseInt(((mxCell) (o)).getValue().toString());
				for(InternalAgentInfo info : queuedAgentsInfo){
					if(info.getStartVertexID().equals(id)){
						graph.setCellStyles(mxConstants.STYLE_FILLCOLOR, mxUtils.getHexColorString(info.getColor()), new Object[]{o});
					}else if(!occupiedIDs.contains(id)){
						graph.setCellStyles(mxConstants.STYLE_FILLCOLOR, null, new Object[]{o});
					}
				}
			}
		}finally{
			model.endUpdate();
		}
	}
	public void colourVertex(Integer vertexID, Color color){
		GraphEditor editor = GraphEditor.getInstance();
		graph = editor.getGraph();
		mxIGraphModel model = graph.getModel();
		model.beginUpdate();
		try{
			for(Object o : graph.getChildVertices(graph.getDefaultParent())){
				Integer id = Integer.parseInt(((mxCell) (o)).getValue().toString());
				if(vertexID.equals(id)){
					graph.setCellStyles(mxConstants.STYLE_FILLCOLOR, color == null ? null : mxUtils.getHexColorString(color), new Object[]{o});
				}				
			}
		}finally{
			model.endUpdate();
		}
	}
	public void viewMove(InternalAgentInfo info, Integer prevID){
		GraphEditor editor = GraphEditor.getInstance();
		graph = editor.getGraph();
		mxIGraphModel model = graph.getModel();
		model.beginUpdate();
		try{
			for(Object o : graph.getChildVertices(graph.getDefaultParent())){
				Integer id = Integer.parseInt(((mxCell) (o)).getValue().toString());
				if(info.getCurrentVertexID().equals(id)){
					graph.setCellStyles(mxConstants.STYLE_FILLCOLOR, mxUtils.getHexColorString(info.getColor()), new Object[]{o});
				}else if (prevID.equals(id)){
					graph.setCellStyles(mxConstants.STYLE_FILLCOLOR, null, new Object[]{o});
				}
				
			}
		}finally{
			model.endUpdate();
		}
	}
	public void log(String log) {
		System.out.println(log);
		mainFrame.getLoggingPanel().appendConsole(log, Level.INFO);
	}
	public void warn(String log){
		System.err.println(log);
		mainFrame.getLoggingPanel().appendConsole(log, Level.WARN);
	}
	public void error(String log){
		System.err.println(log);
		mainFrame.getLoggingPanel().appendConsole(log, Level.ERROR);
	}
	public static void showMessage(String message, MessageType messageType){
		if(mainFrame != null){
			switch (messageType) {
			case INFO:
				JOptionPane.showMessageDialog(mainFrame, message, "Information", JOptionPane.INFORMATION_MESSAGE);
				break;
			case ERROR:
				JOptionPane.showMessageDialog(mainFrame, message, "Error", JOptionPane.ERROR_MESSAGE);
				break;
			case WARNING:
				JOptionPane.showMessageDialog(mainFrame, message, "Warning", JOptionPane.WARNING_MESSAGE);
				break;
			default:
				break;
			}
			
		}
	}
	public static enum MessageType{
		INFO, ERROR, WARNING;
	}
	private void cleanGraph() {
		GraphEditor editor = GraphEditor.getInstance();
		graph = editor.getGraph();
		if(graph != null){
			mxIGraphModel model = graph.getModel();
			model.beginUpdate();
			try{
				graph.setCellStyles(mxConstants.STYLE_FILLCOLOR, null, graph.getChildVertices(graph.getDefaultParent()));			
			}finally{
				model.endUpdate();
			}
		}
	}
	private void cleanAgentTable() {
		mainFrame.getSimulationPanel().fireTableChanged();
	}
	private void cleanDefaultParams(){
		mainFrame.getSimulationPanel().cleanDefaultAgentParams();
	}
	public void newSimulation() {
		cleanGraph();
		cleanAgentTable();
		cleanDefaultParams();
	}
	public void openSummary() {
		SummaryPanel summaryPanel = mainFrame.getSummaryPanel();
		Simulation simulation = PlatformManager.getInstatnce().getSimulation();
		SimulationStatistic statistic = simulation.getStatistic();		
		AgentManager agentManager = simulation.getAgentManager();
		
		summaryPanel.setParam(SummaryPanel.STATE, statistic.state);
		summaryPanel.setParam(SummaryPanel.RATING, statistic.rating.toString());
		summaryPanel.setParam(SummaryPanel.ITERATIONS, statistic.iterations.toString());		
		summaryPanel.setParam(SummaryPanel.MIN_ITERATIONS, statistic.minIterations.toString());
		summaryPanel.setParam(SummaryPanel.AGENTS, statistic.agents.toString());
		summaryPanel.setParam(SummaryPanel.VERTICES, statistic.vertices.toString());
		summaryPanel.setParam(SummaryPanel.EDGES, statistic.edges.toString());
		summaryPanel.setParam(SummaryPanel.TIME, statistic.time.toString() + "ms");
		summaryPanel.setParam(SummaryPanel.OBSERV, agentManager.getObservString());
		summaryPanel.setParam(SummaryPanel.PREDICT, agentManager.getPredictString());
		summaryPanel.setParam(SummaryPanel.RELIE, agentManager.getRelieString());
		
		mainFrame.showSummary();
	}
	public void updateIteration(int iteration) {
		mainFrame.getSimulationPanel().setIteration(iteration);
	}
	public void initMultiRun(int runTime) {
		multirunDialog = new MultirunDialog(runTime, mainFrame);
		multirunDialog.setVisible(true);
	}
	public void multirunProgress(int progress) {
		if(multirunDialog != null){
			multirunDialog.setProgress(progress);
		}
	}
	public void multirunDone(LinkedList<SimulationStatistic> statistics) {
		multirunDialog.setVisible(false);
		multirunDialog = null;
		MultirunSummaryDialog summaryDialog = new MultirunSummaryDialog(statistics, mainFrame);
		summaryDialog.setVisible(true);
	}
	
}
